#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>

int main()
{
    int listenfd = socket(PF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
    {
        perror("socket:");
        exit(1);
    }

    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(5188);
    //设置地址可以重复利用
    int on = 1;
    if ((setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) < 0)
    {
        perror("setsockopt ");
        exit(1);
    }
    int ret = bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    if (ret < 0)
    {
        perror("bind");
        exit(1);
    }

    ret = listen(listenfd, SOMAXCONN);
    if (ret < 0)
    {
        perror("listen");
        exit(1);
    }
    struct sockaddr_in peeraddr;
    socklen_t peeraddrlen = sizeof(peeraddr);
    while (1)
    {
        int connfd = accept(listenfd, (struct sockaddr *)&peeraddr, &peeraddrlen);
        if (connfd < 0)
        {
            perror("accept");
            exit(1);
        }
        printf("ip:%s port:%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));

        pid_t pid = fork(); //创建子进程
        if (pid < 0)
        {
            perror("fork");
            exit(1);
        }
        else if (pid == 0) //子进程处理通信过程
        {
            close(listenfd); //子进程会复制父进程的listened，子进程不需要使用，关闭它即可
            char recvbuf[1024];

            while (1)
            {
                memset(&recvbuf, 0, sizeof(recvbuf));
                int sz = read(connfd, recvbuf, sizeof(recvbuf)); //服务器接收客户端发来的数据
                if (sz < 0)
                {
                    perror("read");
                    exit(1);
                }
                else if (sz == 0)
                {
                    printf("peer close\n");
                    break;
                }
                printf("service accept client: ");
                fputs(recvbuf, stdout);     //服务器打印客户端发来的数据
                write(connfd, recvbuf, sz); //服务端回射给客户端
            }
            exit(1); //客户端关闭，就会跳出到这行,该为客户端服务的子进程就没有存在的价值了
        }
        else //父进程
        {
            close(connfd);
        }
    }

    return 0;
}
